//功能比较齐全了，除开比较新的数据类型无法复制，旧的数据和引用类型都可以复制，可以复制正则和日期
function deepCopy(obj, cache = new WeakMap()) {
    //非引用类型
    //function  set map 这些也是从 Object 继承而来
    if (!obj instanceof Object) return obj;

    //为什么说防止循环引用？——好像真的防，厉害，循环引用的属性不能无限循环下去，否则会内存溢出
    if (cache.get(obj)) {
        return cache.get(obj);
    }
    //函数
    if (obj instanceof Function) {
        return function () {
            //函数可能有返回值，所以要 return
            return obj.apply(this, arguments);
        }
    }

    //日期
    if (obj instanceof Date) return new Date(obj);

    //正则:  RegExp 的 source 属性代表正则文本，flags 代表匹配模式
    if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);

    //不是数组就是对象，然后开始复制
    let res = Array.isArray(obj) ? [] : {};
    cache.set(obj, res);
    //仅赋值了可枚举的属性(不可枚举的难道不能访问？)
    Object.keys(obj).forEach((key) => {
        if (obj[key] instanceof Object) {
            res[key] = deepCopy(obj[key], cache);
        } else {
            res[key] = obj[key];
        }
    });
    return res;
}

const source = {
    name: 'Jack',
    meta: {
        age: 12,
        birth: new Date('1997-10-10'),
        ary: [1, 2, { a: 1 }],
        say() {
            console.log('Hello');
        }
    }
}

source.source = source;
var newObj = deepCopy(source);
console.log(newObj.meta.ary[2]===source.meta.ary[2]);  //false
console.log(newObj.meta.birth===source.meta.birth);  //false
